/*
 * gatewayMain.c
 *
 *  Created on: 2012-5-23
 *      Author: qinsiyuan
 */


#include "stdlix.h"
#include "soc.h"
#include "pthread.h"
/*
 * 工作开关
 * FALSE:启动模式，建立节点地址映射表格，开启接收节点的启动信息的信息，开启向服务器发送开启信息线程
 * TRUE：工作模式，关闭向服务器发送开启信息线程，接收服务器发送的请求，不关闭监听节点
 */
int workSwitch;

/*
 * 线程ID
 */
pthread_t id;

/*
 * 线程属性
 * 所有线程设置为分离线程，防止内存泄漏
 */
pthread_attr_t attr;

/*
 * 适配器函数
 * 监听节点
 */
int listenNode(NodMessage * nodMessage)
{
	return receive_from_node(tunAddress,nodMessage);
}

/*
 * 时间相减函数
 * 用于计算两个时间所差的秒数
 */
int tim_substract(struct timeval *result,struct timeval *x,struct timeval *y)
{
    if(x->tv_sec>y->tv_sec)
        result->tv_sec=86400-x->tv_sec+y->tv_sec;
    else
        result->tv_sec=y->tv_sec-x->tv_sec;
    return 0;
}

/*
 * 适配器函数
 * 向服务器发送消息
 */
int sendServer(ServerMessage * serverMessage)
{
	return send_to_server(serverMessage,SERVER_ADDRESS);
}

/*
 * 节点请求温度和湿度
 * TRUE：成功发送
 * FALSE：发送失败
 */
int requestData(NodMessage * requesteMessage)
{
	return send_to_node(requesteMessage);
}

/*
 * 启动函数，工作开关关闭时调用
 */
void switchOn()
{
	ServerSwitchOn * mess = NULL;
	void serverThread();
	mess = (ServerSwitchOn *)malloc(sizeof(ServerMessage));
	bzero(mess,sizeof(ServerSwitchOn));
	mess->order = GATEWAY_BORN;
	mess->num = gatewayNum * PUBLIC_PRIVATE_GATEWAY_NUM_SWITCH;
	while(!workSwitch)
	{
		workSwitch = sendServer((ServerMessage *)mess);
		sleep(GATEWAY_BURN_SLEEP_TIME);
	}
	pthread_create(&id, &attr, (void*)serverThread, NULL);

	free(mess);
}

/*
 * 适配器函数，与雷雨的函数接口适配
 * 监听服务器消息
 */
int listenServer()
{
	return receive_from_server();
}

/*
 * 处理节点信息
 */
void dealNodeMessage(NodeData * mess)
{
	int i=FALSE;
	char remoteipv6_addr[36];
	if(mess->order == NODE_BORN)//节点出生
	{
		for(i = FALSE;i<MAX_NODE_COUNT;i++)
		{
	        inet_ntop(AF_INET6, &table[i], remoteipv6_addr,sizeof(remoteipv6_addr));
		}
	}
	else if(mess -> order == NODE_HEART || mess -> order == DATA)//向服务器发送温度和湿度信息
	{
		if(workSwitch)
		{
			ServerData * serData = NULL;
			serData = (ServerData *)malloc(sizeof(ServerMessage));
			bzero(serData,sizeof(ServerData));
			serData -> order = mess -> order;
			serData -> num = mess -> num + gatewayNum * PUBLIC_PRIVATE_GATEWAY_NUM_SWITCH /*+ TRUE*/;
			serData -> temperature = mess -> temperature;
			serData -> humidity = mess -> humidity;
			if(mess -> order == NODE_HEART)
			{
				if(workSwitch)
				{
					workSwitch = sendServer((ServerMessage *)serData);
					if(!workSwitch)
					{
						serData->order = STOP_ACCEPT;
						while(!send_to_server(serData,LOOP_BACK_ADDRESS));
					}
				}
			}
			else
			{
				nodebuff[mess -> num-1].message = * (ServerMessage *)serData;
				nodebuff[mess -> num-1].access ++;
			}
			free(serData);
			serData = NULL;
		}
	}
	free(mess);
	mess = NULL;
}

/*
 * 处理服务器信息
 */
void dealServerMessage(int server)
{
	struct timeval start,stop,diff;
	NodForRequest * rquestMessage = NULL;
	ServerMessage * returnMess = NULL;
	ServerMessage * mess = NULL;
	char * httpRequest = NULL;
	int i = 0;
	httpRequest = (char *)malloc(K);
	bzero(httpRequest,K);
	recv(server,httpRequest,K,FALSE);

	mess = (ServerMessage *)strstr(httpRequest,"\r\n\r\n");
	if(mess)
	{
		mess = (ServerMessage *)(((char *)mess)+strlen("\r\n\r\n"));
	}
	else
	{
		if(!httpRequest)
		{
			free(httpRequest);
			httpRequest = NULL;
		}
		if(server)
		{
			close(server);
			server = FALSE;
		}
		return;
	}

	if(mess->order == STOP_ACCEPT)
	{
		if(!httpRequest)
		{
			free(httpRequest);
			httpRequest = NULL;
		}
		if(server)
		{
			close(server);
			server = FALSE;
		}
		return;
	}
	returnMess = (ServerMessage *)malloc(sizeof(ServerMessage));
	memset(returnMess,'\0',sizeof(ServerMessage));
	if(workSwitch)
		switch(mess->order)
		{
			case REQUEST_DATA:
				returnMess -> order = ERROR;
				rquestMessage = (NodForRequest *)malloc(sizeof(NodMessage));
				bzero(rquestMessage,sizeof(NodMessage));
				//转换成节点报文
				rquestMessage->order = mess -> order;
				rquestMessage->num = ((ServerForRequest * )mess)->num - gatewayNum * PUBLIC_PRIVATE_GATEWAY_NUM_SWITCH/* - TRUE*/;
				if(rquestMessage->num > MAX_NODE_COUNT || rquestMessage->num < 1)
				{
					returnMess->order = ERROR;
				}
				else
				{
					char * isNULL = (char *)(table+(rquestMessage->num - 1));
					for(i=0;i<16;i++)
					{
						if(*isNULL)
						{
							returnMess->order = mess->order;
							break;
						}
					}
						if(returnMess->order != ERROR)
						{
							if(requestData((NodMessage *)rquestMessage/*,(NodMessage *)returnMessage*/))
							{
								gettimeofday(&start,0);
								while(!nodebuff[rquestMessage->num - TRUE].access)
								{
									gettimeofday(&stop,0);
									tim_substract(&diff,&start,&stop);
									if(diff.tv_sec>=TIME_LIMITE)
										break;
								}
								//从缓存中复制
								if(diff.tv_sec>=TIME_LIMITE)
									returnMess->order = ERROR;
								else
								{
									nodebuff[rquestMessage->num - TRUE].access --;
									*returnMess = nodebuff[rquestMessage->num - TRUE].message;
								}
							}
							else
							{
								//转换成服务器报文
								returnMess->order = ERROR;
							}
						}
					}
				break;
			case REQUEST_IP_ADDRESS:
				//获取地址
				returnMess->order = NO_IP_ADDRESS;
				((ServerForNodAddress *)returnMess)->num = ((ServerForRequest * )mess)->num;
				if(((ServerForNodAddress *)returnMess)->num - gatewayNum * PUBLIC_PRIVATE_GATEWAY_NUM_SWITCH - TRUE > 6 //越界
						|| ((ServerForNodAddress *)returnMess)->num - gatewayNum * PUBLIC_PRIVATE_GATEWAY_NUM_SWITCH - TRUE < 0) //越界
				{
					returnMess ->order = NO_IP_ADDRESS;
				}
				else
				{
					*((struct in6_addr *)(((ServerForNodAddress *)returnMess)->ipaddress)) = table[((ServerForNodAddress * )returnMess)->num - gatewayNum * PUBLIC_PRIVATE_GATEWAY_NUM_SWITCH - TRUE];
				}
				for(i = 3;i < 19; i++)
				{
					if((returnMess->data[i]))
					{
						returnMess->order = mess -> order;
						break;
					}
				}
				break;
			default:
				returnMess->order = ERROR;
		}
	if(rquestMessage != NULL)
	{
		free(rquestMessage);
		rquestMessage = NULL;
	}
	if(returnMess != NULL)
	{
		if(workSwitch)
		{
			int headSize = 0,i = 0;
			bzero(httpRequest,K);
			headSize = getReponseHTTPHead(httpRequest);
			httpRequest[headSize]=returnMess->order;
			for(i = 0;i < SERVER_MESSAGE_DATA_LENGTH;i++)
				httpRequest[headSize+TRUE+i] = returnMess->data[i];
			send(server,httpRequest,headSize+SERVER_MESSAGE_DATA_LENGTH+TRUE,FALSE);
			if(!workSwitch)
			{
				returnMess->order = STOP_ACCEPT;
				send_to_server(returnMess,LOOP_BACK_ADDRESS);
			}
		}
		free(returnMess);
		returnMess = NULL;
	}
	if(httpRequest != NULL)
	{
		free(httpRequest);
		mess = NULL;
		httpRequest = NULL;
	}
	close(server);
}

/*
 * 服务器线程
 */
void serverThread()
{
	int server = FALSE;
	do
	{
		server = listenServer();
		if(server>=FALSE)
		{
			pthread_create(&id,&attr,(void *)dealServerMessage, server);
		}
	}while(workSwitch);
	pthread_create(&id, &attr, (void*)switchOn, NULL);
}

/*
 *从文件中读取tun地址和编号设置信息
 */
void getSettings(FILE * fp)
{
	char order[10];
	char value[64];
	while(!feof(fp))
	{
		if(EOF != fscanf(fp,"%s %s\n",order,value))
		{
			if(!strcmp(order,"tunAddress"))
			{
				strcpy(tunAddress,value);
			}
			else if(!strcmp(order,"gatewayNum"))
			{
				gatewayNum = atoi(value);
				if(gatewayNum < 111)
					gatewayNum = DEFAULT_GATEWAY_NUM;
			}
		}
		else
		{
			break;
		}
	}
}
/*
 * 打印帮助信息
 */
void printHelp()
{
	printf("\t可以不带参数\n");
	printf("\t-tun:设置tun口地址\n");
	printf("\t-gwn:设置网关编号\n");
	printf("\t-h:帮助信息\n");
}
/*
 * 主函数
 * 启动新线程用于监听节点
 * 启动新线程用于向服务器发送出生信息
 * 主线程监听服务器
 */
int main(int argc,char ** argv)
{
	int j = 0;
	NodMessage * mess = NULL;
	FILE * fp = NULL;
	/*
	 * 如果有参数，直接将参数作为地址，并写入文件
	 * 如果没参数，默认从文件中读取地址
	 * 如果文件打开失败，用默认地址,并尝试将默认地址写入文件
	 * 如果参数错误或请求帮助信息，则显示帮助信息并退出程序
	 */
	strcpy(tunAddress,TUN_ADDRESS);
	gatewayNum = DEFAULT_GATEWAY_NUM;

	/*
	 * 有参数的情况
	 */
	if(argc-TRUE)
	{
		if(argc > 5||!(argc % 2))
		{
			printf("参数错误\n");
			printHelp();
			exit(FALSE);
		}
		else
		{
			for(j=TRUE;j<argc;j+=2)
			{
				if(!strcmp(argv[j],"-tun"))
					strcpy(tunAddress,argv[j+TRUE]);
				else if(!strcmp(argv[j],"-gwn"))
				{
					gatewayNum = atoi(argv[j+TRUE]);
					if(!(gatewayNum % PUBLIC_PRIVATE_GATEWAY_NUM_SWITCH))
					{
						gatewayNum = gatewayNum / PUBLIC_PRIVATE_GATEWAY_NUM_SWITCH;
					}
					if(gatewayNum < DEFAULT_GATEWAY_NUM)
					{
						gatewayNum = DEFAULT_GATEWAY_NUM;
					}
					if(!((gatewayNum % PUBLIC_PRIVATE_GATEWAY_NUM_SWITCH) && ((gatewayNum % 100)/PUBLIC_PRIVATE_GATEWAY_NUM_SWITCH)))
					{
						gatewayNum = DEFAULT_GATEWAY_NUM;
					}
				}
				else if(!strcmp(argv[j],"-h"))
				{
					printHelp();
					exit(FALSE);
				}
				else
				{
					printf("参数错误！\n");
					printHelp();
					exit(FALSE);
				}
			}
			fp = fopen(SETTINGS_ADDRESS,"w");
			if(fp)
			{
				fprintf(fp,"tunAddress %s\n",tunAddress);
				fprintf(fp,"gatewayNum %d\n",gatewayNum);
				fclose(fp);
			}
		}
	}
	else
	{
		strcpy(tunAddress,TUN_ADDRESS);
		gatewayNum = DEFAULT_GATEWAY_NUM;
		fp = fopen(SETTINGS_ADDRESS,"r");
		if(fp)
		{
			getSettings(fp);
			if(fp)
				fclose(fp);
		}
		else
		{
			fp = fopen(SETTINGS_ADDRESS,"w");
			if(fp)
			{
				fprintf(fp,"tunAddress %s\n",tunAddress);
				fprintf(fp,"gatewayNum %d\n",gatewayNum);
				fclose(fp);
			}
		}
	}

//雷雨 start
	for(j = FALSE;j<=6;j++)
	{
	        data_seq[j]=17;
	        heart_seq[j]=17;
	}
//雷雨 end
	/*
	 * 初始化线程属性
	 */
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);

	//出生线程
	pthread_create(&id, &attr, (void*)switchOn, NULL);

	//主线程负责与节点通讯
	do
	{
		mess = (NodMessage *)malloc(sizeof(NodMessage));
		bzero(mess,sizeof(NodMessage));
		if(listenNode(mess))
		{
			pthread_create(&id, &attr, (void*)dealNodeMessage, mess);
		}
		else
		{
			free(mess);
		}
		mess = NULL;
	}while(TRUE);
}
